package cn.virens.cmpt.server;

import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.virens.cmpt.server.channel.Channel;
import cn.virens.cmpt.server.channel.ChannelSimple;
import cn.virens.cmpt.server.handler.AsynchronousSocketAcceptHandler;
import cn.virens.cmpt.server.listener.DataDecoder;
import cn.virens.cmpt.server.listener.DataEncoder;
import cn.virens.cmpt.server.listener.DataErrorListener;
import cn.virens.cmpt.server.listener.DataHandlerListener;
import cn.virens.cmpt.server.listener.DataReadListener;
import cn.virens.cmpt.server.listener.DataWriteListener;
import cn.virens.cmpt.server.listener.OnChannelCloseableListener;
import cn.virens.cmpt.server.listener.OnChannelConnectedListener;
import cn.virens.cmpt.server.listener.OnChannelExceptionListener;
import cn.virens.main.AppConfig;
import cn.virens.main.cmpt.Component;

public class ServerManageImpl implements ServerManage, Component {
	private final Logger logger = LoggerFactory.getLogger(ServerManageImpl.class);

	private AsynchronousChannelGroup channelGroup = null;

	private AsynchronousServerSocketChannel serverSocketChannel;
	private AsynchronousSocketAcceptHandler socketAcceptHandler;

	private ExecutorService groupExecutor = null;
	private ExecutorService wokerExecutor = null;

	// 数据解码/编码器
	private DataDecoder dataDecoder;
	private DataEncoder dataEncoder;

	// 数据操作监听事件
	private DataReadListener dataReadListener;
	private DataWriteListener dataWriteListener;
	private DataErrorListener dataErrorListener;
	private DataHandlerListener dataHandlerListener;

	// 连接状态监听事件
	private OnChannelConnectedListener onChannelConnectedListener;
	private OnChannelCloseableListener onChannelCloseableListener;
	private OnChannelExceptionListener onChannelExceptionListener;

	private String host;
	private Integer port;

	private boolean isWaitStop;

	@Override
	public void initialize(AppConfig config) throws Exception {
		this.groupExecutor = Executors.newCachedThreadPool();
		this.wokerExecutor = Executors.newCachedThreadPool();

		this.channelGroup = AsynchronousChannelGroup.withThreadPool(groupExecutor);
		this.serverSocketChannel = AsynchronousServerSocketChannel.open(channelGroup);
		this.socketAcceptHandler = AsynchronousSocketAcceptHandler.newInstance(this);

		this.serverSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
		this.serverSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 64 * 1024);

		this.host = config.getString("server.host");
		this.port = config.getInteger("server.port");

		if (host == null || host.isEmpty()) {
			this.serverSocketChannel.bind(new InetSocketAddress(port), 0);
			this.serverSocketChannel.accept(null, socketAcceptHandler);
		} else {
			this.serverSocketChannel.bind(new InetSocketAddress(host, port), 0);
			this.serverSocketChannel.accept(null, socketAcceptHandler);
		}
	}

	@Override
	public boolean isWaitStop() {
		return isWaitStop;
	}

	@Override
	public String getHost() {
		return host;
	}

	@Override
	public Integer getPort() {
		return port;
	}

	@Override
	public void send(Channel channel, Packet packet) {
		ChannelSimple channelSimple = (ChannelSimple) channel;

		// 获取对应的连接通道的写操作线程，并放进去执行发送
		channelSimple.getChannelWriteRunnable().offer(packet);
		channelSimple.getChannelWriteRunnable().execute();
	}

	@Override
	public void send(String uid, Packet packet) {
		this.send(getChannel(uid), packet);
	}

	@Override
	public void bindUid(Channel channel, String uid) {
		this.socketAcceptHandler.bindUid(channel, uid);
	}

	@Override
	public void unbindUid(Channel channel) {
		this.socketAcceptHandler.unbindUid(channel);
	}

	@Override
	public Channel getChannel(String uid) {
		return socketAcceptHandler.getChannel(uid);
	}

	public AsynchronousChannelGroup getChannelGroup() {
		return channelGroup;
	}

	public ExecutorService getGroupExecutor() {
		return groupExecutor;
	}

	public ExecutorService getWokerExecutor() {
		return wokerExecutor;
	}

	public AsynchronousServerSocketChannel getServerSocketChannel() {
		return serverSocketChannel;
	}

	public AsynchronousSocketAcceptHandler getSocketAcceptHandler() {
		return socketAcceptHandler;
	}

	public DataDecoder getDataDecoder() {
		return dataDecoder;
	}

	public void setDataDecoder(DataDecoder dataDecoder) {
		this.dataDecoder = dataDecoder;
	}

	public DataEncoder getDataEncoder() {
		return dataEncoder;
	}

	public void setDataEncoder(DataEncoder dataEncoder) {
		this.dataEncoder = dataEncoder;
	}

	public DataReadListener getDataReadListener() {
		return dataReadListener;
	}

	public void setDataReadListener(DataReadListener dataReadListener) {
		this.dataReadListener = dataReadListener;
	}

	public DataWriteListener getDataWriteListener() {
		return dataWriteListener;
	}

	public void setDataWriteListener(DataWriteListener dataWriteListener) {
		this.dataWriteListener = dataWriteListener;
	}

	public DataErrorListener getDataErrorListener() {
		return dataErrorListener;
	}

	public void setDataErrorListener(DataErrorListener dataErrorListener) {
		this.dataErrorListener = dataErrorListener;
	}

	public DataHandlerListener getDataHandlerListener() {
		return dataHandlerListener;
	}

	public void setDataHandlerListener(DataHandlerListener dataHandlerListener) {
		this.dataHandlerListener = dataHandlerListener;
	}

	public OnChannelConnectedListener getOnChannelConnectedListener() {
		return onChannelConnectedListener;
	}

	public void setOnChannelConnectedListener(OnChannelConnectedListener mOnChannelConnectListener) {
		this.onChannelConnectedListener = mOnChannelConnectListener;
	}

	public OnChannelCloseableListener getOnChannelCloseableListener() {
		return onChannelCloseableListener;
	}

	public void setOnChannelCloseableListener(OnChannelCloseableListener mOnChannelCloseableListener) {
		this.onChannelCloseableListener = mOnChannelCloseableListener;
	}

	public OnChannelExceptionListener getOnChannelExceptionListener() {
		return onChannelExceptionListener;
	}

	public void setOnChannelExceptionListener(OnChannelExceptionListener mOnChannelExceptionListener) {
		this.onChannelExceptionListener = mOnChannelExceptionListener;
	}

	@Override
	public void destroy() throws Exception {
		try {
			this.channelGroup.shutdownNow();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}

		try {
			this.serverSocketChannel.close();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}

		try {
			this.groupExecutor.shutdownNow();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}

		try {
			this.wokerExecutor.shutdownNow();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
	}
}
